﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using DBMS.Models;
using DBMS.Models.DataInterfaces;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using DBMS.Helpers.Application;
using DBMS.Helpers.Metadata;

namespace DBMS.Data
{
    public class ValueRepository : IValueRepository
    {
        public IList<Value> GetRow(int rowId)
        {
            throw new NotImplementedException();
        }

        public void SaveOrUpdate(int databaseId, int tableId, Value value)
        {
            MetadataManager metadataManager = new MetadataManager();
            int tempIndex = metadataManager.GetLastIndexForTable(databaseId, tableId);
            value.Id = tempIndex++;
            metadataManager.SetLastIndexForTable(value.Id, databaseId, tableId);
            metadataManager.SetLastRowForTable(value.RowId, databaseId, tableId);

            SetCurrentDirectoryToAppDir();
            string colPath = "databases//" + databaseId + "//" + tableId + "//V_" + value.RowId + "_" + value.Id;

            Stream stream = File.Open(colPath, FileMode.OpenOrCreate);
            BinaryFormatter bformatter = new BinaryFormatter();
            bformatter.Serialize(stream, value);
            stream.Close();
        }


        public IList<Value> GetValuesForColumn(int databaseId, int tableId, int columnId)
        {
            SetCurrentDirectoryToAppDir();

            IList<Value> values = new List<Value>();
            string[] valueFiles = Directory.GetFiles("databases//" + databaseId.ToString() + "//" + tableId.ToString());


            ColumnRepository columnRepository = new ColumnRepository();
            Column column = columnRepository.GetColumn(databaseId, tableId, columnId);

            foreach (string valueFile in valueFiles)
            {
                if (valueFile.Contains("V"))
                {
                    Stream stream = File.Open(valueFile, FileMode.Open);
                    BinaryFormatter bformatter = new BinaryFormatter();
                    Value value = (Value)bformatter.Deserialize(stream);
                    stream.Close();

                    if (!value.Deleted)
                    {
                        if (value.ColumnId == columnId)
                        {
                            //value.Column = column;
                            values.Add(value);
                        }
                    }
                }
            }

            return values;
        }


        public IList<Value> GetValuesForTable(int databaseId, int tableId)
        {
            SetCurrentDirectoryToAppDir();

            IList<Value> values = new List<Value>();
            string[] valueFiles = Directory.GetFiles("databases//" + databaseId.ToString() + "//" + tableId.ToString());

            foreach (string valueFile in valueFiles)
            {
                if (valueFile.Contains("V"))
                {
                    Stream stream = File.Open(valueFile, FileMode.Open);
                    BinaryFormatter bformatter = new BinaryFormatter();
                    Value value = (Value)bformatter.Deserialize(stream);
                    stream.Close();

                    if (!value.Deleted)
                    {
                        values.Add(value);
                    }
                }
            }

            return values.OrderBy(x => x.RowId).ToList();
        }

        private void SetCurrentDirectoryToAppDir()
        {
            string appPath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
            Directory.SetCurrentDirectory(appPath);
        }


        public void SaveMultipleValues(int databaseId, int tableId, int columnCount, IEnumerable<string> values)
        {
            MetadataManager metadataManager = new MetadataManager();
            int tempIndex = metadataManager.GetLastIndexForTable(databaseId, tableId);
            int lastRow = metadataManager.GetLastRowForTable(databaseId, tableId);
            tempIndex++;
            lastRow++;

            int counter = 0;

            ColumnRepository columnRepository = new ColumnRepository();

            IList<Column> columns = columnRepository.GetAllColumnsForTable(databaseId, tableId);

            SetCurrentDirectoryToAppDir();

            foreach (String temp in values)
            {
                Value value = new Value();
                value.Id = tempIndex;
                value.ColumnId = columns.ElementAt(counter).Index;
                tempIndex++;
                value.RowId = lastRow;
                counter++;
                if (counter == columnCount)
                {
                    lastRow++;
                    counter = 0;
                }

                value.ConcreteValue = temp;

                string colPath = "databases//" + databaseId + "//" + tableId + "//V_" + value.RowId + "_" + value.Id;

                Stream stream = File.Open(colPath, FileMode.OpenOrCreate);
                BinaryFormatter bformatter = new BinaryFormatter();
                bformatter.Serialize(stream, value);
                stream.Close();
            }

            metadataManager.SetCountersForTable(tempIndex, lastRow - 1, databaseId, tableId);
        }


        public void UpdateMultipleValues(int databaseId, int tableId, int rowId, IEnumerable<string> newValues)
        {
            SetCurrentDirectoryToAppDir();

            IList<Value> oldValues = new List<Value>();
            string[] valueFiles = Directory.GetFiles("databases//" + databaseId.ToString() + "//" + tableId.ToString());

            foreach (string valueFile in valueFiles)
            {
                if (valueFile.Contains("V"))
                {
                    Stream stream = File.Open(valueFile, FileMode.Open);
                    BinaryFormatter bformatter = new BinaryFormatter();
                    Value value = (Value)bformatter.Deserialize(stream);
                    stream.Close();

                    if (value.RowId == rowId)
                    {
                        oldValues.Add(value);
                    }
                }
            }

            int i = 0;

            foreach (Value value in oldValues)
            {
                value.ConcreteValue = newValues.ElementAt(i);
                i++;

                string colPath = "databases//" + databaseId + "//" + tableId + "//V_" + value.RowId + "_" + value.Id;

                Stream stream = File.Open(colPath, FileMode.Truncate);
                BinaryFormatter bformatter = new BinaryFormatter();
                bformatter.Serialize(stream, value);
                stream.Close();
            }


        }


        public void DeleteRow(int databaseId, int tableId, int rowId)
        {
            SetCurrentDirectoryToAppDir();

            IList<Value> oldValues = new List<Value>();
            string[] valueFiles = Directory.GetFiles("databases//" + databaseId.ToString() + "//" + tableId.ToString());

            foreach (string valueFile in valueFiles)
            {
                if (valueFile.Contains("V"))
                {
                    Stream stream = File.Open(valueFile, FileMode.Open);
                    BinaryFormatter bformatter = new BinaryFormatter();
                    Value value = (Value)bformatter.Deserialize(stream);
                    stream.Close();

                    if (value.RowId == rowId)
                    {
                        oldValues.Add(value);
                    }
                }
            }

            foreach (Value value in oldValues)
            {
                value.Deleted = true;

                string colPath = "databases//" + databaseId + "//" + tableId + "//V_" + value.RowId + "_" + value.Id;

                Stream stream = File.Open(colPath, FileMode.Truncate);
                BinaryFormatter bformatter = new BinaryFormatter();
                bformatter.Serialize(stream, value);
                stream.Close();
            }
        }
    }
}